package net.entelijan.cobean.filesel;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.ListCellRenderer;
import javax.swing.SwingUtilities;
import javax.swing.plaf.basic.BasicComboBoxRenderer;

import net.entelijan.cobean.core.DialogReturnValue;
import net.entelijan.cobean.core.ICobean;
import net.entelijan.cobean.core.IInitializer;
import net.entelijan.cobean.core.impl.AbstractBoundPropertyValueComponentBean;
import net.entelijan.cobean.util.GuiActionListener;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class DefaultFileselInitializer implements IInitializer<ICobean<File>> {

	private static Log log = LogFactory.getLog(DefaultFileselInitializer.class);

	private IFileselDAO dao = new FilesystemFileselDAO();

	private int maxProposalSize = 10;

	private IFileFilter fileFilter;

	private String id;

	private FileSelectionMode fileSelectionMode = FileSelectionMode.FILES_ONLY;

	private IFileChooser chooser = new DefaultFileChooser();

	private JComboBox coComboBox;

	private JButton coButton;

	private Component parent;

	public DefaultFileselInitializer() {
		super();
	}

	public ICobean<File> initialize() {
		
		if (this.id == null) {
			throw new IllegalArgumentException("id must be defined for the filesel initializer");
		}

		ListCellRenderer renderer = new BasicComboBoxRenderer() {

			private static final long serialVersionUID = 1L;

			public Component getListCellRendererComponent(JList list,
					Object value, int index, boolean isSelected,
					boolean cellHasFocus) {
				JLabel re = (JLabel) super.getListCellRendererComponent(list,
						value, index, isSelected, hasFocus());
				int width = coComboBox.getWidth();
				if (width > 0) {
					float size2D = coComboBox.getFont().getSize() * 0.53f;
					int maxWidth = (int) (width / size2D);
					String abbreviate = value == null ? "" : abbreviate(
							(String) value, maxWidth);
					re.setText(abbreviate);
				} else {
					re.setText((String) value);
				}
				return re;
			}

		};

		// Init the filechooser
		if (this.fileFilter != null) {
			chooser.setFileFilter(this.fileFilter);
		}
		chooser.setFileSelectionMode(fileSelectionMode);

		coComboBox.setRenderer(renderer);

		coComboBox.setEditable(true);
		final FileselComboBoxModel model = new FileselComboBoxModel(dao
				.loadProposals(id), this.maxProposalSize);
		coComboBox.setModel(model);
		final ComponentBean re = new ComponentBean(coComboBox, id,
				fileSelectionMode);
		coComboBox.addActionListener(new ActionListener() {

			@Override
			public void actionPerformed(ActionEvent e) {
				re.firePropertyChanged();
				dao.saveProposals(id, model.getValuesToStore());
			}

		});
		if (coButton == null) {
			throw new IllegalStateException(
					"You must define a chooser button for the fileselection");
		}
		coButton.addActionListener(new GuiActionListener(SwingUtilities
				.getRoot(coButton)) {

			public void guiActionPerformed(ActionEvent e) {
				String sel = (String) coComboBox.getSelectedItem();
				if (sel != null && sel.length() > 0) {
					File selFile = new File(sel);
					if (selFile.isDirectory()) {
						chooser.setCurrentDirectory(selFile.getParentFile());
					} else {
						chooser.setSelectedFile(selFile);
					}
				}
				DialogReturnValue returnVal = chooser.showOpenDialog(parent);
				if (returnVal == DialogReturnValue.OK) {
					log.debug("You chose to open this file: "
							+ chooser.getSelectedFile().getName());
					String newValue = chooser.getSelectedFile()
							.getAbsolutePath();
					FileselComboBoxModel model = (FileselComboBoxModel) coComboBox
							.getModel();
					model.setSelectedItem(newValue);
					dao.saveProposals(id, model.getValuesToStore());
				}
			}

		});
		return re;
	}

	private String abbreviate(String path, int maxWidth) {
		String re;
		int i = path.lastIndexOf(File.separator) + 1;
		if (i < 0) {
			re = StringUtils.abbreviate(path, maxWidth);
		} else {
			String fname = path.substring(i);
			String pathname = path.substring(0, i);
			if (fname.length() > maxWidth) {
				re = StringUtils.abbreviate(fname, maxWidth);
			} else {
				int mw = maxWidth - fname.length();
				if (mw == 0) {
					re = fname;
				} else if (mw == 1) {
					re = "." + fname;
				} else if (mw == 2) {
					re = ".." + fname;
				} else if (mw == 3) {
					re = "..." + fname;
				} else {
					re = StringUtils.abbreviate(pathname, mw) + fname;
				}
			}
		}
		return re;
	}

	private final class ComponentBean extends
			AbstractBoundPropertyValueComponentBean<File> {

		private JComboBox proposalBox;

		private String id;

		private FileSelectionMode fileSelectionMode;

		public ComponentBean(JComboBox proposalBox, String id,
				FileSelectionMode fileSelectionMode) {
			this.proposalBox = proposalBox;
			this.id = id;
			this.fileSelectionMode = fileSelectionMode;
		}

		@Override
		public void firePropertyChanged() {
			propertyChangeSupport.firePropertyChange("value", null,
					getValuePlain());
		}

		@Override
		public File getValuePlain() {
			File re = null;
			String selectedPath = (String) this.proposalBox.getModel()
					.getSelectedItem();
			if (selectedPath != null) {
				re = new File(selectedPath);
			}
			return re;
		}

		@Override
		public void setValuePlain(File value) {
			if (value == null) {

			} else {
				if (fileSelectionMode == FileSelectionMode.DIRECTORIES_ONLY
						&& value.exists() && !value.isDirectory()) {
					throw new IllegalArgumentException(
							"Only directories are allowed for that file chooser. Not "
									+ value);
				}
				if (fileSelectionMode == FileSelectionMode.FILES_ONLY
						&& value.exists() && !value.isFile()) {
					throw new IllegalArgumentException(
							"Only files are allowed for that file chooser. Not "
									+ value);
				}
				String path = value.getAbsolutePath();
				FileselComboBoxModel model = (FileselComboBoxModel) this.proposalBox
						.getModel();
				model.setSelectedItem(path);
				dao.saveProposals(id, model.getValuesToStore());
			}
		}
	}

	public IFileselDAO getDao() {
		return dao;
	}

	public void setDao(IFileselDAO dao) {
		this.dao = dao;
	}

	public int getMaxProposalSize() {
		return maxProposalSize;
	}

	public void setMaxProposalSize(int maxProposalSize) {
		this.maxProposalSize = maxProposalSize;
	}

	public IFileFilter getFileFilter() {
		return fileFilter;
	}

	public void setFileFilter(IFileFilter filter) {
		this.fileFilter = filter;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public FileSelectionMode getFileSelectionMode() {
		return fileSelectionMode;
	}

	public void setFileSelectionMode(FileSelectionMode fileSelectionMode) {
		this.fileSelectionMode = fileSelectionMode;
	}

	public Component getParent() {
		return parent;
	}

	public void setParent(Component parent) {
		this.parent = parent;
	}

	public IFileChooser getChooser() {
		return chooser;
	}

	public void setChooser(IFileChooser chooser) {
		this.chooser = chooser;
	}

	public JComboBox getCoComboBox() {
		return coComboBox;
	}

	public void setCoComboBox(JComboBox coComboBox) {
		this.coComboBox = coComboBox;
	}

	public JButton getCoButton() {
		return coButton;
	}

	public void setCoButton(JButton coButton) {
		this.coButton = coButton;
	}

}
